#include "multicastclient.h"
#include <windows.h>
#include <tchar.h>
#include <QElapsedTimer>
#include <QNetworkInterface>
#include <QTcpSocket>
#include "DataType.h"

#ifdef _UNICODE
typedef std::wstring STRING;
#else
typedef std::string STRING;
#endif
const size_t NPOS = STRING::npos;

const TCHAR* Qt5AppClassName = _T("Qt5QWindowIcon");
const TCHAR* AxisAppName[] = {
	_T("Axis Legacy"),
	_T("Axis Neuron")
};

BOOL CALLBACK MyEnumWindowsProc(HWND hWnd, LPARAM lParam) {
	TCHAR* clsName = new TCHAR[32];
	::GetClassName(hWnd, clsName, 32);
	if (_tcscmp(Qt5AppClassName, clsName) != 0) {
		return TRUE;
	}
	delete[] clsName;

	int len = ::GetWindowTextLength(hWnd);
	TCHAR* titleS = new TCHAR[len + 1];
	::GetWindowText(hWnd, titleS, len + 1);
	STRING title(titleS);
	delete[] titleS;

	if ((title.find(AxisAppName[0], 0) != NPOS) || (title.find(AxisAppName[1], 0) != NPOS)) {
		*(HWND*)lParam = hWnd;
		return FALSE;
	}
	else {
		return TRUE;
	}
}

HWND MulticastClient::MyFindAxisWindow() {
	HWND hMainWnd_ = 0;
	::EnumWindows(MyEnumWindowsProc, (LPARAM)&hMainWnd_);
	if (!hMainWnd_) {
		ui.msgLabel->setText("Axis software not running...");
		return 0;
	}
	else {
		return hMainWnd_;
	}
}

HWND MyFindWindow(int which)
{
	TCHAR* A_szWinName[2] = {
		_T("Record Settings"),
		_T("MotionCaptureToolBarWindow")
	};

	HWND hLastWin = ::FindWindow(Qt5AppClassName, A_szWinName[which]);
	return hLastWin;
}

void ClickRecordButton(HWND hMainWnd_) {
	::SetForegroundWindow(hMainWnd_);
	::SetFocus(hMainWnd_);
	::keybd_event(VK_CONTROL, 0, 0, 0);
	::keybd_event('R', 0, 0, 0);
	::keybd_event('R', 0, KEYEVENTF_KEYUP, 0);
	::keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
}

void MulticastClient::StartRecord() {
	HWND hWnd_RecordSettings = MyFindWindow(0);
	if (!hWnd_RecordSettings) {
		ClickRecordButton(hMainWnd);
		hWnd_RecordSettings = MyFindWindow(0);
		if (!hWnd_RecordSettings) {
			QElapsedTimer timer;
			timer.start();
			while (!timer.hasExpired(2000)) {
				QCoreApplication::processEvents();
				hWnd_RecordSettings = MyFindWindow(0);
				if (hWnd_RecordSettings) {
					break;
				}
			}
		}
	}
	if (!hWnd_RecordSettings) {
		ui.msgLabel->setText("Please open [Record Settings] window...");
		return;
	}

	::SetForegroundWindow(hMainWnd);
	::SetFocus(hWnd_RecordSettings);

	::keybd_event(VK_RETURN, 0, 0, 0);
	::keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
}




void MulticastClient::StopRecord()
{
	ClickRecordButton(hMainWnd);
}

MulticastClient::MulticastClient(QWidget *parent)
	: QMainWindow(parent)
	, target(nullptr)
	, collectors(5)
{
	ui.setupUi(this);

	udpCommandController = new QUdpSocket(this);
	connect(ui.pushButton_StartRecord, &QPushButton::clicked, this, &MulticastClient::SendCommand_StartRecord);
	connect(ui.pushButton_StopRecord, &QPushButton::clicked, this, &MulticastClient::SendCommand_StopRecord);

	for (int i = 0; i < 5; i++) {
		collectors[i] = new QTcpSocket(this);
		connect(collectors[i], &QIODevice::readyRead, this, &MulticastClient::forwardData);
	}

	if (server.listen(QHostAddress::AnyIPv4)) {
		//QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
		//// use the first non-localhost IPv4 address
		//for (int i = 0; i < ipAddressesList.size(); ++i) {
		//	if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
		//		ipAddressesList.at(i).toIPv4Address()) {
		//		ipAddress = ipAddressesList.at(i).toString();
		//		break;
		//	}
		//}
		//// if we did not find one, use IPv4 localhost
		//if (ipAddress.isEmpty()) {
		//	ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
		//}
		ui.label_serverinfo->setText(tr("The server is running on\n\nIP: %1\nport: %2")
			.arg(server.serverAddress().toString()).arg(server.serverPort()));

		connect(&server, &QTcpServer::newConnection, this, &MulticastClient::acceptConnection);
	}

	groupAddress = QHostAddress("239.255.33.44");
	udpSocket = new QUdpSocket(this);
	//udpSocket->bind(QHostAddress::AnyIPv4, 8877, QUdpSocket::ShareAddress);
	if (udpSocket->bind(8877, QUdpSocket::ShareAddress)) {
		ui.msgLabel->setText("bind ok.");
	}
	else {
		ui.msgLabel->setText("bind failed.");
	}
	/*if (udpSocket->joinMulticastGroup(groupAddress)) {
		ui.msgLabel->setText("join group succeed.");
	}
	else {
		ui.msgLabel->setText("join group failed.");
	}*/

	connect(udpSocket, SIGNAL(readyRead()),
		this, SLOT(processPendingDatagrams()));

	connect(ui.pushButton_src_connect, &QPushButton::clicked,
		this, &MulticastClient::collectData);
}

MulticastClient::~MulticastClient()
{

}

void MulticastClient::processPendingDatagrams()
{
	hMainWnd = MyFindAxisWindow();
	if (!hMainWnd) {
		ui.msgLabel->setText("Please run Axis software...");
		return;
	}

	while (udpSocket->hasPendingDatagrams()) {
		QByteArray datagram;
		datagram.resize(udpSocket->pendingDatagramSize());
		udpSocket->readDatagram(datagram.data(), datagram.size());
		ui.msgLabel->setText(QString("Received Datagram: ").append(datagram));
		bool ok;
		int i = datagram.toInt(&ok);
		if (ok) {
			if (i == eStartRecord) {
				StartRecord();
			}
			else if (i == eStopRecord) {
				StopRecord();
			}
		}
	}
}

void MulticastClient::collectData()
{
	static QVector<QPair<QLineEdit*, QLineEdit*>> lineEditors{
		{ui.lineEdit_src_ip1, ui.lineEdit_src_port1},
		{ui.lineEdit_src_ip2, ui.lineEdit_src_port2},
		{ui.lineEdit_src_ip3, ui.lineEdit_src_port3},
		{ui.lineEdit_src_ip4, ui.lineEdit_src_port4},
		{ui.lineEdit_src_ip5, ui.lineEdit_src_port5}
	};

	for (int i = 0; i < 5; i++) {
		auto& ip_editor   = lineEditors[i].first;
		auto& port_editor = lineEditors[i].second;
		collectors[i]->abort();

		QHostAddress addr;
		if (addr.setAddress(ip_editor->text())) {
			bool ok;
			auto port = port_editor->text().toUShort(&ok);
			if (ok) {
				collectors[i]->connectToHost(addr, port);
				continue;
			}
		}
	}
}

void MulticastClient::forwardData()
{
	QTcpSocket* sock = (QTcpSocket*)(sender());
	auto bytes = sock->readAll();
	BvhDataHeader* header=nullptr;

	if (target) {
		int i = 0;
		for (; i < 5; i++) {
			if (sock == collectors[i]) {
				*(int*)(bytes.begin() + (int)&(header->AvatarIndex)) = i;
				target->write(bytes);
				break;
			}
		}
	}
}

void MulticastClient::acceptConnection()
{
	if (!target && server.hasPendingConnections()) {
		target = server.nextPendingConnection();
	}
}

void MulticastClient::SendCommand_StartRecord()
{
	SendCommand(eStartRecord);
}

void MulticastClient::SendCommand_StopRecord()
{
	SendCommand(eStopRecord);
}

void MulticastClient::SendCommand(MulticastClient::CommandType cmd)
{
	QByteArray datagram(QByteArray::number(cmd));
	udpCommandController->writeDatagram(datagram.data(), datagram.size(),
		QHostAddress::Broadcast, 8877);
}

